from tkinter import *
from tkinter import ttk
from tkinter import constants,filedialog
from tkinter import messagebox

import win32clipboard
from urllib import parse
import os,sys
import json


from util.time import *
from util.trans import *
from util.divide_text_by_lines import *
from util.hanzi import *

LOG_LINE_NUM = 0

# MOCO = "D:\\桌面\\小工具\\little_tool\\"
# MOCO_CONFIG_PATH = MOCO+'config.json'
# MOCO_PATH = MOCO+'moco-runner-1.1.0-standalone.jar'
# MOCO_START_BAT_PATH = MOCO+'start.bat"
# MOCO_STOP_BAT_PATH = MOCO+'stop.bat"
# MOCO_VBS_PATH = MOCO+'start.vbs"
# MOCO_LOG_PATH = MOCO+'moco.log"
MOCO_PORT = "10012"


class EditAddMocoDialog(Toplevel):
    '''
    接口新增/编辑界面
    '''
    def __init__(self,Interface):
        super().__init__()
        self.name = Interface['name']
        self.method = Interface['method']
        self.url = Interface['url']
        self.content = Interface['content']
        self.title('编辑/新建模拟接口')
        # 弹窗界面
        self.setup_UI()
    def setup_UI(self):
        # 第一行（两列）
        width_all = 100
        row1 = Frame(self)
        row1.pack(fill="x")
        Label(row1, text='接口名称：', width=8).pack(side=LEFT)
        # self.name = StringVar()
        self.name_Entry = Entry(row1, width=width_all)
        self.name_Entry.insert(0,self.name)
        self.name_Entry.pack(side=LEFT)
        # 第二行
        row2 = Frame(self)
        row2.pack(fill="x", ipadx=1, ipady=1)
        Label(row2, text='接口类型', width=8).pack(side=LEFT)
        # self.age = IntVar()
        self.method_Entry = Entry(row2, width=width_all)
        self.method_Entry.insert(0,self.method)
        self.method_Entry.pack(side=LEFT)
        # 第三行
        row3 = Frame(self)
        row3.pack(fill="x", ipadx=1, ipady=1)
        Label(row3, text='url', width=8).pack(side=LEFT)
        # self.age = IntVar()
        self.url_Entry = Entry(row3, width=width_all)
        self.url_Entry.insert(0,self.url)
        self.url_Entry.pack(side=LEFT)
        # 第四行
        row4 = Frame(self)
        row4.pack(fill="x", ipadx=1, ipady=1)
        Label(row4, text='返回内容', width=8).pack(side=LEFT)
        # self.age = IntVar()
        self.content_Text = Text(row4, width=width_all)
        self.content_Text.insert(1.0,self.content)
        self.content_Text.pack(side=LEFT)
        # 第五行
        row5 = Frame(self)
        row5.pack(fill="x")
        Button(row5, text="取消", command=self.cancel).pack(side=RIGHT)
        Button(row5, text="确定", command=self.ok).pack(side=RIGHT)
    def ok(self):
        self.name = self.name_Entry.get()
        self.method = self.method_Entry.get()
        self.url = self.url_Entry.get()
        self.content = self.content_Text.get(1.0,END)
        self.userinfo = [self.name, self.method, self.url, self.content] # 设置数据
        self.destroy() # 销毁窗口
    def cancel(self):
        self.userinfo = [self.name, self.method, self.url, self.content] # 返回原值！
        self.destroy()
    

#获取当前时间
def get_current_time():
    current_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
    return current_time

#日志动态打印
def write_log_to_Text(logmsg):
    global LOG_LINE_NUM
    log_data_Text.config(state=NORMAL)
    current_time = get_current_time()
    logmsg_in = str(current_time) +" " + str(logmsg) + "\n"      #换行
    if LOG_LINE_NUM <= 7:
        log_data_Text.insert(END, logmsg_in)
        LOG_LINE_NUM = LOG_LINE_NUM + 1
    else:
        log_data_Text.delete(1.0,2.0)
        log_data_Text.insert(END, logmsg_in)
    log_data_Text.config(state=DISABLED)

def str_trans_hbase():
    src = input_data_Text.get(1.0,END).strip().replace("\n","")
    if src:
        try:
            resultData = strans(src)
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,resultData)
            # write_log_to_Text("INFO: success")
        except:
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,"字符串转失败")
    else:
        print("error!")
        # write_log_to_Text("ERROR: failed")


def str_trans_url():
    src = input_data_Text.get(1.0,END).strip().replace("\n","").encode()
    if src:
        try:
            resultData = parse.unquote(strans(src))
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,resultData)
            # write_log_to_Text("INFO: success")
        except:
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,"字符串转失败")
    else:
        print("error!")
        # write_log_to_Text("ERROR: failed")

def str_trans_time():
    src = input_data_Text.get(1.0,END).strip()
    if src:
        try:
            resultData = time_trans(src)
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,resultData)
            src_times = src.split("\n")
            out_times = resultData.split("\n")
            for i, src_time in enumerate(src_times):
                write_log_to_Text("INFO: "+src_time+" To: "+out_times[i])
        except:
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,"字符串转失败")
    else:
        write_log_to_Text("ERROR: failed") 

def str_get_time():
    time_now = time.time()
    stamp_now = str(int(round(time_now*1000)))
    resultData = "时间戳为：     " + stamp_now + "\n时间格式显示： " + stamp_to_date(stamp_now)
    result_data_Text.delete(1.0,END)
    result_data_Text.insert(1.0,resultData)

def hans2hant():
    src = input_data_Text.get(1.0,END).strip()
    if src:
        try:
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,hans_2_hant(src))
        except:
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,"字符串转失败")
    else:
        write_log_to_Text("ERROR: failed") 

def hant2hans():
    src = input_data_Text.get(1.0,END).strip()
    if src:
        try:
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,hant_2_hans(src))
        except:
            result_data_Text.delete(1.0,END)
            result_data_Text.insert(1.0,"字符串转失败")
    else:
        write_log_to_Text("ERROR: failed") 

def clear_data():
    result_data_Text.delete(1.0,END)
    input_data_Text.delete(1.0,END)


def clear_datalog():
    global LOG_LINE_NUM
    log_data_Text.delete(1.0,END)
    LOG_LINE_NUM = 0

def copyresultdata():
    copystring = result_data_Text.get(1.0,END)[:-1]
    win32clipboard.OpenClipboard()
    win32clipboard.EmptyClipboard()
    win32clipboard.SetClipboardText(copystring,win32clipboard.CF_TEXT)
    win32clipboard.CloseClipboard()
    write_log_to_Text("INFO: 复制结果到剪贴板")

def page2selectfile():

    # get filename
    filename = filedialog.askopenfilename(initialdir="C:\\",title="This is title",parent=page2)
    page2_file_path_Text.delete(1.0,END)
    page2_file_path_Text.insert(1.0,filename)

def page2selectpath():
    # get filename
    filename = filedialog.askdirectory(initialdir="C:\\",title="This is title",parent=page2)
    page2_path_Text.delete(1.0,END)
    page2_path_Text.insert(1.0,filename)

def page3selectfile():
    filename = filedialog.askopenfilename(initialdir="C:\\",title="This is title",parent=page2)
    page3_file_path_Text.delete(1.0,END)
    page3_file_path_Text.insert(1.0,filename)

def page3selectpath():
    # get filename
    filename = filedialog.askdirectory(initialdir="C:\\",title="This is title",parent=page2)
    page3_path_Text.delete(1.0,END)
    page3_path_Text.insert(1.0,filename)

trans_model_dic={"hbase转换":0,"url编码转换":1,"简体转繁体":2,"繁体转简体":3}
trans_model_list = list(trans_model_dic.keys())

switch = {
    'hbase转换': strans,
    '简体转繁体': hans_2_hant,
    '繁体转简体': hant_2_hans,
    'url编码转换':strans_url
}

def tran_file():
    global trans_model_dic
    input_file_name = page2_file_path_Text.get(1.0,END)[:-1]
    output_path_name = page2_path_Text.get(1.0,END)[:-1]
    if output_path_name == '' or (not os.path.exists(output_path_name)):
        output_path_name = "D:/"
        msg = get_current_time() + "\t输出路径为空或者不存在，使用默认输出路径：  D:/\n"
        page2logText.insert(END,msg)
    input_file_name_ex = os.path.splitext(os.path.basename(input_file_name))
    print (input_file_name_ex)
    output_file_name = os.path.join(output_path_name,input_file_name_ex[0]+"stran"+input_file_name_ex[1])
    mode = trans_model_list[v.get()]
    print(mode)
    msg = get_current_time() + "\t开始将文件"+input_file_name+"进行"+mode+"，输出至文件"+output_file_name + "\n"
    page2logText.insert(END,msg)
    if os.path.exists(input_file_name) and os.path.isfile(input_file_name) :
        outputFile = open(output_file_name,"w", encoding="utf-8")
        with open(input_file_name, encoding="utf-8") as inputFile:
            i = 0
            line = inputFile.readline()
            while (line):
                output_string = switch.get(mode, strans)(line)
                outputFile.writelines(output_string)
                line = inputFile.readline()
                i = i+1
                if i%1000 == 0:
                    msg = get_current_time() + "\t已经处理"+str(i)+"行数据\n"
                    page2logText.insert(END,msg)
        outputFile.close()
        msg = get_current_time() + "\t转换完成！请查看输出文件："+output_file_name + "\n"
        page2logText.insert(END,msg)

    else:
        error_string = get_current_time() + "\t输入的文件不存在！\n"
        page2logText.insert(END,error_string)

def page3divide():
    input_file = page3_file_path_Text.get(1.0,END)[0:-1]
    output_path = page3_path_Text.get(1.0,END)[0:-1]
    try:
        divide_lines = int(page3_get_small_file_lins_Text.get(1.0,END)[0:-1])
        divide_number = int(page3_get_small_file_number_Text.get(1.0,END)[0:-1])
        if os.path.isfile(input_file) and os.path.isdir(output_path):
            divide_text_by_line(big_file=input_file,small_file_lines=divide_lines,new_file_path=output_path,times=divide_number)
            messagebox.showwarning('消息','转换完成！')
        else:
            messagebox.showwarning('警告','输入文件路径错误或者输出路径错误！')
            print("输入文件路径错误或者输出路径错误！")
    except Exception as errors:
        messagebox.showwarning('警告','请输入数字')
        print(str(errors)) 
    
def page5_treeview_sort_column(tv, col, reverse):  # Treeview、列名、排列方式
    l = [(tv.set(k, col), k) for k in tv.get_children('')]
    l.sort(reverse=reverse)  # 排序方式
    # rearrange items in sorted positions
    for index, (val, k) in enumerate(l):  # 根据排序后索引移动
        tv.move(k, '', index)
    tv.heading(col, command=lambda: page5_treeview_sort_column(tv, col, not reverse))  # 重写标题，使之成为再点倒序的标题
 
def page5_edit(event): # 双击进入编辑状态
    selection = page5_treeview.selection()
    print(selection.count)
    num = page5_treeview.index(selection)
    print(num)
    inputDialog = EditAddMocoDialog({'name':name[num],'method':method[num],'url':url[num],'content':content[num]})
    page5_treeview.wait_window(inputDialog) # 这一句很重要！！！
    newinfo = inputDialog.userinfo
    if newinfo is None: return
    page5_treeview.set(selection,column=1,value=newinfo[0])
    page5_treeview.set(selection,column=2,value=newinfo[1])
    page5_treeview.set(selection,column=3,value=newinfo[2])
    name[num] = newinfo[0]
    method[num] = newinfo[1]
    url[num] = newinfo[2]
    content[num] = newinfo[3]
    print(newinfo)
    number = []
    for j in range(len(name)):
        number.append(j+1)
    write_mock_config({'number':number,'name':name,'url':url,"method":method, "content":content})

 
def page5_add():
    inputDialog = EditAddMocoDialog({'name':'','method':'','url':'','content':''})
    page5_treeview.wait_window(inputDialog) # 这一句很重要！！！
    newinfo = inputDialog.userinfo
    # 判断输入的信息是否符合规范
    try:
        output_json_string = newinfo[3]
        print(output_json_string)
        output_json = json.loads(output_json_string)
    except:
        messagebox.showwarning('警告','输入的接口返回值格式错误不是json,添加失败')
        return
    name.append(newinfo[0])
    method.append(newinfo[1])
    url.append(newinfo[2])
    content.append(newinfo[3])
    i = len(name)-1
    number.append(str(i+1))
    print(i)
    page5_treeview.insert('', i, values=(number[i], name[i], method[i], url[i]))
    print(newinfo)
    write_mock_config({'number':number,'name':name,'url':url,"method":method, "content":content})

def write_mock_config(config):
    number = config['number']
    name = config['name']
    method = config['method']
    url = config['url']
    content = config['content']
    config_list = []
    for i in number:
        j = int(i)-1
        config_item = {
        "description": "",
        "request": {
            "uri": "",
            "method": ""
        },
        "response": {
			"json":{"code":200}
        }}
        config_item['description'] = name[j]
        config_item['request']['method'] = method[j]
        config_item['request']['uri'] = url[j]
        config_item["response"]["json"] = json.loads(content[j])
        config_list.append(config_item)
    global MOCO_CONFIG_PATH
    f = open(MOCO_CONFIG_PATH, "w", encoding="utf-8")
    config_string = json.dumps(config_list).encode('latin-1').decode('unicode_escape')
    f.write(config_string)
    f.close()

def read_mock_cofig():
    global MOCO_CONFIG_PATH
    number = []
    name = []
    method = []
    url = []
    content = []

    # 获取已有接口配置信息
    print(MOCO_CONFIG_PATH)
    config_file = open(MOCO_CONFIG_PATH, "r", encoding="utf-8")
    config_dic = json.load(config_file)
    i = 1
    for config in config_dic:
        number.append(str(i))
        name.append(config['description'])
        method.append(config['request']['method'])
        url.append(config['request']['uri'])
        content.append(json.dumps(config['response']['json']).encode('latin-1').decode('unicode_escape'))
        i  = i+1
    return number,name,method,url,content

def on_closing():
    os.system(MOCO_STOP_BAT_PATH)
    little_tools.destroy()

def delete_iterm():
    num = page5_treeview.index(popup.selection)
    print(num)
    page5_treeview.delete(popup.selection)
    name.pop(num)
    url.pop(num)
    content.pop(num)
    method.pop(num)
    number.pop()
    print(name)
    print(url)
    print(content)
    print(method)
    print(number)
    write_mock_config({'number':number,'name':name,'url':url,"method":method, "content":content})

def page5_item_menu(event):
    
    # display the popup menu
    try:
        # popup.selection = page5_treeview.set(page5_treeview.identify_row(event.y))
        popup.selection = page5_treeview.selection()
        popup.post(event.x_root, event.y_root)
    finally:
        # make sure to release the grab (Tk 8.0a1 only)
        popup.grab_release()
    print ("0")
    

if __name__ == '__main__':
    MOCO = sys.argv[1]
    MOCO_CONFIG_PATH = MOCO+'config.json'
    MOCO_PATH = MOCO+'moco-runner-1.1.0-standalone.jar'
    MOCO_START_BAT_PATH = MOCO+'start.bat'
    MOCO_STOP_BAT_PATH = MOCO+'stop.bat'
    MOCO_VBS_PATH = MOCO+'start.vbs'
    MOCO_LOG_PATH = MOCO+'moco.log'
    little_tools = Tk()
    little_tools.title("小工具v1.1")
    little_tools.geometry('1068x681')

    universal_height = 1068
    nb = ttk.Notebook(little_tools)
    # adding Frames as pages for the ttk.Notebook
    # first page, which would get widgets gridded into it
    page1 = ttk.Frame(nb,width = 681,height = universal_height)
    # second page
    page2 = ttk.Frame(nb,width = 681,height = universal_height)
    page3 = ttk.Frame(nb,width = 681,height = universal_height)
    page4 = ttk.Frame(nb,width = 681,height = universal_height)
    page5 = ttk.Frame(nb,width = 681,height = universal_height)
    nb.add(page1, text='输入转换')
    nb.add(page2, text='文档转换')
    nb.add(page3, text='大文件分割')
    # nb.add(page4, text='文件格式转换')
    nb.add(page5, text='接口模拟')
    nb.grid()

    # 第一个选项卡
    #标签
    init_data_label = Label(page1, text="待处理数据")
    init_data_label.grid(row=0, column=0)
    result_data_label = Label(page1, text="输出结果")
    result_data_label.grid(row=0, column=12)
    log_label = Label(page1, text="日志")
    log_label.grid(row=12, column=0)
    #文本框
    input_data_Text = Text(page1, width=67, height=35)  #原始数据录入框
    input_data_Text.grid(row=1, column=0, rowspan=10, columnspan=10)
    result_data_Text = Text(page1, width=70, height=49)  #处理结果展示
    result_data_Text.grid(row=1, column=12, rowspan=15, columnspan=10)
    log_data_Text = Text(page1, width=66, height=9, state = DISABLED)  # 日志框
    log_data_Text.grid(row=13, column=0, columnspan=10)
    #按钮
    page_one_button = Button(page1, text="hbase转换", bg="lightblue", width=10,command=str_trans_hbase)  # 
    page_one_button.grid(row=1, column=11)
    page_one_button = Button(page1, text="url编码转换", bg="lightblue", width=10,command=str_trans_url)  # 
    page_one_button.grid(row=2, column=11)
    page_one_button = Button(page1, text="时间转换", bg="lightblue", width=10,command=str_trans_time)  # 调用内部方法  
    page_one_button.grid(row=3, column=11)
    page_one_button = Button(page1, text="获取当前时间", bg="lightblue", width=10,command=str_get_time)  # 
    page_one_button.grid(row=4, column=11)
    page_one_button = Button(page1, text="简体转繁体", bg="lightblue", width=10,command=hans2hant)  # 调用内部方法  
    page_one_button.grid(row=5, column=11)
    page_one_button = Button(page1, text="繁体转简体", bg="lightblue", width=10,command=hant2hans)  # 调用内部方法  
    page_one_button.grid(row=6, column=11)
    page_one_button = Button(page1, text="清空数据", bg="lightblue", width=10,command=clear_data)  # 调用内部方法  
    page_one_button.grid(row=7, column=11)
    page_one_button = Button(page1, text="复制结果", bg="lightblue", width=10,command=copyresultdata)  # 调用内部方法  
    page_one_button.grid(row=8, column=11)
    page_one_button = Button(page1, text="清空日志", bg="lightblue", width=10,command=clear_datalog)  # 调用内部方法  
    page_one_button.grid(row=12, column=1)

    # 第二个选项卡
    text_width = 130
    Label(page2, text="输入文件").grid(row=0,column=0, sticky=W)
    Label(page2, text="输出路径").grid(row=1,column=0, sticky=W)
    Label(page2, text="转换模式").grid(row=3,column=0, sticky=W)
    Label(page2, text="日志").grid(row=8,column=0, sticky=W+N)
    button_opt = {'fill': constants.BOTH}
    # font_text = tf.Font(family='宋体',size=14)
    page2_file_path_Text = Text(page2,width=text_width, height=1)
    page2_file_path_Text.grid(row=0,column=1)
    Button(page2, text = "文件选择", command = page2selectfile).grid(row = 0, column = 2, sticky=W)
    page2_path_Text = Text(page2,width=text_width, height=1)
    page2_path_Text.grid(row=1,column=1)
    Button(page2, text = "路径选择", command = page2selectpath).grid(row = 1, column = 2, sticky=W)
    # 单选规则
    v = IntVar()
    v.set(1)
    Radiobutton(page2,text ="hbase转换",variable = v,value =0).grid(row=3,column=1, sticky=W)
    Radiobutton(page2,text ="url编码转换",variable = v,value =1).grid(row=4,column=1,  sticky=W)
    Radiobutton(page2,text ="简体转繁体",variable = v,value =2).grid(row=5,column=1,  sticky=W)
    Radiobutton(page2,text ="繁体转简体",variable = v,value =3).grid(row=6,column=1,  sticky=W)
    # 转换按键
    Button(page2, text="开始转换",command=tran_file).grid(row = 3, column = 2,  sticky=W)
    # 输出log框
    page2logText = Text(page2,width=text_width+10, height=30, state = NORMAL)
    page2logText.grid(row=8,column=1,columnspan=2)

    # 第三个选项卡
    Label(page3, text="大文件选择:").grid(row=0,column=0, sticky=E)
    Label(page3, text="输出路径选择:").grid(row=1,column=0, sticky=E)
    Label(page3, text="输出小文件行数:").grid(row=2,column=0, sticky=E)
    Label(page3, text="输出小文件个数:").grid(row=2,column=2, sticky=E)
    page3_file_path_Text = Text(page3,width=text_width, height=1)
    page3_file_path_Text.grid(row=0,column=1,columnspan=4)
    Button(page3, text = "文件选择", command = page3selectfile).grid(row = 0, column = 5, sticky=W)
    page3_path_Text = Text(page3,width=text_width, height=1)
    page3_path_Text.grid(row=1,column=1,columnspan=4)
    page3_get_small_file_lins_Text = Text(page3,width=20,height=1)
    page3_get_small_file_lins_Text.grid(row=2,column=1, sticky=W)
    page3_get_small_file_lins_Text.insert(1.0,1000)
    page3_get_small_file_number_Text = Text(page3,width=20,height=1)
    page3_get_small_file_number_Text.grid(row=2,column=3, sticky=W)
    page3_get_small_file_number_Text.insert(1.0,30)
    Button(page3, text = "路径选择", command = page3selectpath).grid(row = 1, column = 5, sticky=W)
    Button(page3, text = "开始转换", command = page3divide).grid(row = 2, column = 5, sticky=W)

    # 第5选项卡
    columns = ("序号", "接口名称","类型","url","状态")
    page5_treeview = ttk.Treeview(page5,  show="headings", columns=columns)  # 表格
    page5_treeview.column("序号", anchor='center') # 表示列,不显示
    page5_treeview.column("接口名称", anchor='center')
    page5_treeview.column("类型",  anchor='center')
    page5_treeview.column("url", anchor='center') # 表示列,不显示
    page5_treeview.heading("序号", text="序号") # 显示表头
    page5_treeview.heading("接口名称", text="接口名称")
    page5_treeview.heading("类型", text="类型")
    page5_treeview.heading("url", text="url") # 显示表头
    page5_treeview.grid(row=1,column=1)
    number,name,method,url,content = read_mock_cofig()
    for i in range(min(len(number),len(name))): # 写入数据
        print(i)
        page5_treeview.insert('', i, values=(number[i], name[i], method[i], url[i]))
    # 双击左键进入编辑
    page5_treeview.bind('<Double-1>', page5_edit) 
    # 单机右键键进入功能选择菜单
    page5_treeview.bind('<Button-3>', page5_item_menu) 
    popup = Menu(page5, tearoff=0)
    popup.add_command(label="delete", command=delete_iterm)
    # popup.add_command(label="edit", command=page5_edit)
    popup.add_separator()

    # 新建接口按键
    page5_newb = Button(page5, text='新建接口', width=20, command=page5_add)
    page5_newb.grid(row=0,column=1,sticky=E)
    # 启动MOCO
    string_bat = "java -Dfile.encoding=UTF-8 -jar " + MOCO_PATH  + " start -p "+MOCO_PORT+" -c " + MOCO_CONFIG_PATH + " > " + MOCO_LOG_PATH
    with open (MOCO_START_BAT_PATH,"w",encoding="ANSI") as file_:
        file_.writelines(string_bat)
    with open(MOCO_VBS_PATH,"w",encoding="ANSI") as file_:
        file_.writelines("Set ws = CreateObject(\"Wscript.shell\")\nws.run \"cmd /c " + MOCO_START_BAT_PATH + "\",vbhide")
    os.system(MOCO_VBS_PATH)
    Label(page5,text="默认端口：" + MOCO_PORT).grid(row=0,column=1,sticky=W)
    for col in columns:  # 绑定函数，使表头可排序
        page5_treeview.heading(col, text=col, command=lambda _col=col: page5_treeview_sort_column(page5_treeview, _col, False))

    little_tools.protocol("WM_DELETE_WINDOW",on_closing)
    little_tools.mainloop() 